package io.github.luons.mediator.dsl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.luons.mediator.core.constant.Constant;
import io.github.luons.mediator.core.enums.Keyword;
import io.github.luons.mediator.core.enums.Operator;
import io.github.luons.mediator.core.utils.EnumUtils;
import io.github.luons.mediator.core.utils.JacksonUtils;
import io.github.luons.mediator.dsl.handler.RequestHolder;
import io.github.luons.mediator.dsl.service.BaseQueryService;
import io.github.luons.mediator.dsl.utils.MediatorUtils;
import io.github.luons.mediator.dsl.utils.WrapperUtils;
import io.github.luons.mediator.dsl.view.FilterGroupsRequest;
import io.github.luons.mediator.dsl.view.filter.FilterGroup;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * BaseQueryServiceImpl
 *
 * @author : luons
 */
public class BaseQueryServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<BaseMapper<T>, T> implements BaseQueryService<T> {

    @Autowired
    private M baseMapper;

    public BaseQueryServiceImpl() {
    }

    @Override
    public List<T> findAndSearchByEntity(T entity) {
        return baseMapper.selectList(createWrapper(entity));
    }

    @Override
    public List<T> findAndSearchByMap(Map<String, Object> params) {
        return baseMapper.selectList(createWrapper(params));
    }

    @Override
    public List<T> findAndSearchByFilters() {
        return baseMapper.selectList(createWrapper(RequestHolder.getFilterGroupsRequest()));
    }

    @Override
    public <R> List<R> findAndSearchByFilters(Class<R> clazz) {
        // TODO number is must be set scale
        List<Map<String, Object>> data = baseMapper.selectMaps(createWrapper(RequestHolder.getFilterGroupsRequest()));
        return JacksonUtils.parseAsList(data, clazz);
    }

    @Override
    public List<Map<String, Object>> findAndSearchMapsByFilters() {
        return baseMapper.selectMaps(createWrapper(RequestHolder.getFilterGroupsRequest()));
    }

    /**
     * create QueryWrapper
     *
     * @param request request
     * @param <T>     T
     * @return QueryWrapper
     */
    public static <T> QueryWrapper<T> createWrapper(FilterGroupsRequest request) {
        if (Objects.isNull(request)) {
            return new QueryWrapper<>();
        }
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        // filter
        for (FilterGroup group : request.getFilters()) {
            Operator operator = EnumUtils.getEnumByName(Operator.class, group.getOperator().toUpperCase());
            if (Objects.isNull(operator)) {
                continue;
            }
            // TODO 暂时写死为转换为下划线
            String groupName = MediatorUtils.convertEnhanced(group.getName());
            WrapperUtils.applyCondition(wrapper, groupName, operator, group.getValues());
        }
        // order
        if (StringUtils.isNotBlank(request.getOrderFields())) {
            boolean isAsc = Keyword.ASC.getName().equals(request.getOrderBy());
            List<String> columns = Arrays.asList(request.getOrderFields().split(Constant.COMMA));
            if (isAsc) {
                wrapper.orderByAsc(columns);
            } else {
                wrapper.orderByDesc(columns);
            }
        }
        // dimension
        if (CollectionUtils.isNotEmpty(request.getDimensions())) {
            WrapperUtils.applyDimension(wrapper, request.getDimensions(), request.getMeasures());
        }
        return wrapper;
    }

    /**
     * create QueryWrapper(Default eq)
     *
     * @param paramsMap paramsMap
     * @param <T>       T
     * @return QueryWrapper
     */
    public static <T> QueryWrapper<T> createWrapper(Map<String, Object> paramsMap) {
        if (MapUtils.isEmpty(paramsMap)) {
            return new QueryWrapper<>();
        }
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        paramsMap.entrySet().stream().filter(entry -> Objects.nonNull(entry.getValue())).forEach(entry -> wrapper.eq(entry.getKey(), entry.getValue()));
        return wrapper;
    }

    /**
     * create QueryWrapper(Default eq)
     *
     * @param entity entity
     * @param <T>    T
     * @return QueryWrapper
     */
    public static <T> QueryWrapper<T> createWrapper(T entity) {
        if (Objects.isNull(entity)) {
            return new QueryWrapper<>();
        }
        return createWrapper(JacksonUtils.bean2Map(entity));
    }

}